using Nop.Core;
using Nop.Core.Data;
using Nop.Core.Domain;
using Nop.Core.Domain.Customers;
using Nop.Core.Domain.Directory;
using Nop.Core.Domain.Orders;
using Nop.Core.Domain.Payments;
using Nop.Core.Domain.Stores;
using Nop.Core.Plugins;
using Nop.Services.Common;
using Nop.Services.Configuration;
using Nop.Services.Customers;
using Nop.Services.Directory;
using Nop.Services.Logging;
using Nop.Services.Orders;
using Nop.Services.Payments;
using Spotshub.Plugin.Payments.GlobalPayments.Controllers;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Routing;
using Nop.Services.Localization;
using Spotshub.Plugin.Payments.GlobalPayments.Services;
using System.Text;

namespace Spotshub.Plugin.Payments.GlobalPayments
{
    /// <summary>
    /// GlobalPayments payment processor
    /// </summary>
    public class GlobalPaymentsProcessor : BasePlugin, IPaymentMethod
    {
        #region Constants

        public static string PaymentMethodBySystemName = "Payments.GlobalPayments";
        public static string SessionIdKeyName = "session";
        public static string SelectedCreditCardKeyName = "creditcard";

        #endregion

        #region Fields

        private readonly GlobalPaymentsSettings _globalPaymentsSettings;
        private readonly ISettingService _settingService;
        private readonly ICurrencyService _currencyService;
        private readonly ICustomerService _customerService;
        private readonly CurrencySettings _currencySettings;
        private readonly IWebHelper _webHelper;
        private readonly IOrderTotalCalculationService _orderTotalCalculationService;
        private readonly StoreInformationSettings _storeInformationSettings;
        private readonly IWorkContext _workContext;
        private readonly IMobileDeviceHelper _mobileDeviceHelper;
        private readonly HttpContextBase _httpContext;
        private readonly ILogger _logger;

        private readonly IRepository<PaymentCreditCard> _creditCardRepository;
        private readonly IRepository<PaymentProfile> _profileRepository;
        private readonly IRepository<PaymentTransaction> _transactionRepository;

        private readonly GlobalPaymentsObjectContext _objectContext;

        private readonly IGlobalPaymentsService _globalPaymentsService;
        private readonly ILocalizationService _localizationService;

        private readonly IOrderService _orderService;
        #endregion

        #region Ctor

        public GlobalPaymentsProcessor(GlobalPaymentsSettings globalPaymentsSettings,
            ISettingService settingService, ICurrencyService currencyService,
            ICustomerService customerService, ILogger logger,
            IGlobalPaymentsService globalPaymentsService,
            ILocalizationService localizationService,
            IOrderService orderService,
            CurrencySettings currencySettings, IWebHelper webHelper, IOrderTotalCalculationService orderTotalCalculationService,
            StoreInformationSettings storeInformationSettings, IWorkContext workContext,
            IMobileDeviceHelper mobileDeviceHelper, HttpContextBase httpContext,
            IRepository<PaymentCreditCard> creditCardRepository,
            IRepository<PaymentProfile> profileRepository,
            IRepository<PaymentTransaction> transactionRepository,
            GlobalPaymentsObjectContext objectContext)
        {
            this._globalPaymentsSettings = globalPaymentsSettings;
            this._settingService = settingService;
            this._currencyService = currencyService;
            this._customerService = customerService;
            this._globalPaymentsService = globalPaymentsService;
            this._localizationService = localizationService;
            this._currencySettings = currencySettings;
            this._webHelper = webHelper;
            this._orderTotalCalculationService = orderTotalCalculationService;
            this._storeInformationSettings = storeInformationSettings;
            this._workContext = workContext;
            this._mobileDeviceHelper = mobileDeviceHelper;
            this._httpContext = httpContext;
            this._logger = logger;
            this._creditCardRepository = creditCardRepository;
            this._profileRepository = profileRepository;
            this._transactionRepository = transactionRepository;
            this._orderService = orderService;
            this._objectContext = objectContext;
        }

        #endregion

        #region Methods
        /// <summary>
        /// Send Message To GT to refund
        /// </summary>
        /// <param name="url"></param>
        /// <param name="CRESecureID"></param>
        /// <param name="CRESecureAPIToken"></param>
        /// <param name="reversal_type"></param>
        /// <param name="transaction_id"></param>
        /// <param name="reversal_amount"></param>
        /// <param name="order_id"></param>
        /// <returns></returns>
        public string SendRequest(string url, string CRESecureID, string CRESecureAPIToken, string reversal_type, string transaction_id, string reversal_amount, string order_id)
        {

            Helper.FileLog(
                   "PaymentInfo",
                    "GlobalPaymentsProcessor_SendRequest url:" + url + ",CRESecureID=" + CRESecureID + ",CRESecureAPIToken=" + CRESecureAPIToken + ",reversal_type=" + reversal_type + ",transaction_id:" + transaction_id + ",reversal_amount:" + reversal_amount + ",order_id=" + order_id,
                   _globalPaymentsSettings.EnableLog);

            StringBuilder url_Builder = new StringBuilder(url);
            url_Builder.Append("?CRESecureID=").Append(CRESecureID);
            url_Builder.Append("&CRESecureAPIToken=").Append(CRESecureAPIToken);
            url_Builder.Append("&reversal_type=").Append(reversal_type);
            url_Builder.Append("&transaction_id=").Append(transaction_id);
            url_Builder.Append("&reversal_amount=").Append(reversal_amount);
            url_Builder.Append("&order_id=").Append(order_id);

            Helper.FileLog(
                   "PaymentInfo",
                    "GlobalPaymentsProcessor_SendRequest GetCode:" + url_Builder.ToString(),
                   _globalPaymentsSettings.EnableLog);
            return HttpGet(url_Builder.ToString());

            //return url_Builder.ToString();
        }

        public string SendRequestToken(string url, string CRESecureID, string CRESecureAPIToken, string transaction_id, string reversal_amount)
        {
            Helper.FileLog(
                   "PaymentInfo",
                    "GlobalPaymentsProcessor_SendRequestToken url:" + url + "CRESecureID:" + CRESecureID + "CRESecureAPIToken" + CRESecureAPIToken + "transaction_id" + transaction_id + "reversal_amount" + reversal_amount,
                   _globalPaymentsSettings.EnableLog);
            StringBuilder url_Builder = new StringBuilder(url);
            url_Builder.Append("?CRESecureID=").Append(CRESecureID);
            url_Builder.Append("&CRESecureAPIToken=").Append(CRESecureAPIToken);
            url_Builder.Append("&total_amt=").Append(reversal_amount);
            url_Builder.Append("&CRE_Card_Token=").Append(transaction_id);
            url_Builder.Append("&pass_thru=true");

            Helper.FileLog(
                "PaymentInfo",
                 "GlobalPaymentsProcessor_SendRequestToken getCode:" + url_Builder.ToString(),
                _globalPaymentsSettings.EnableLog);
            return HttpGet(url_Builder.ToString());
        }

        /// <summary>
        /// Get code value
        /// </summary>
        /// <param name="result"></param>
        /// <returns></returns>
        private string GetResultCode(string result)
        {
            string[] results = result.Split('&');
            foreach (string a in results)
            {
                if (a.Contains("code"))
                {
                    result = a.Replace("code=", "");
                }
            }
            return result;
        }

        private string GetResultCode(string result, string getName)
        {
            string[] results = result.Split('&');
            foreach (string a in results)
            {
                if (a.Contains(getName))
                {
                    result = a.Replace(getName + "=", "");
                }
                result = HttpUtility.UrlDecode(result.Replace("+", " "));
            }
            return result;
        }

        /// <summary>
        /// help us to get http wevRequest
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public string HttpGet(string url)
        {
            string retString = "";
            try
            {
                if (String.IsNullOrEmpty(url))
                {
                    throw new ArgumentException("url mush has a value");
                }
                HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
                request.Method = "GET";
                request.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";
                request.Timeout = 8000;
                HttpWebResponse response = request.GetResponse() as HttpWebResponse;

                using (Stream responseStream = response.GetResponseStream())
                {
                    StreamReader myStreamReader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8"));
                    retString = myStreamReader.ReadToEnd();
                    myStreamReader.Close();
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return retString;
        }

        /// <summary>
        /// Process a payment
        /// </summary>
        /// <param name="processPaymentRequest">Payment info required for an order processing</param>
        /// <returns>Process payment result</returns>
        public ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest)
        {
            var result = new ProcessPaymentResult();

            result.AllowStoringCreditCardNumber = false;

            //only for test use
            if (this._globalPaymentsSettings.EnableDebug)
            {
                result.NewPaymentStatus = PaymentStatus.Paid;
                return result;
            }
            var cc = new PaymentCreditCard();
            if (processPaymentRequest.CreditCardId > 0)
                cc = _globalPaymentsService.GetCreditCardById(processPaymentRequest.CreditCardId);
            else
                cc = _globalPaymentsService.GetCreditCardById((int)processPaymentRequest.CustomValues[CustomValues.CreditCardId]);
            if (cc != null && cc.CustomerId == processPaymentRequest.CustomerId)
            {
                var res = _globalPaymentsService.RepeatSale(cc.Id, processPaymentRequest.OrderTotal, processPaymentRequest.OrderId > 0 ? processPaymentRequest.OrderId.ToString() : processPaymentRequest.OrderGuid.ToString());
                if (res.Success)
                {
                    result.NewPaymentStatus = PaymentStatus.Paid;


                    var transId = res.TransactionId;
                    //var onePaymentsTransaction = _transactionRepository.Table.FirstOrDefault(i => i.CreditCardId == processPaymentRequest.CreditCardId && i.OrderId == 0);
                    var creditCard = _creditCardRepository.Table.FirstOrDefault(c => c.Id == processPaymentRequest.CreditCardId);

                    var checkOrderInTransaction = _transactionRepository.Table.FirstOrDefault(i => i.CreditCardId == cc.CustomerId && i.OrderId == processPaymentRequest.OrderId);
                    if (checkOrderInTransaction != null)
                        return result;

                    var getTransaction = new transaction();
                    if (creditCard != null && !String.IsNullOrEmpty(creditCard.RawResult))
                    {
                        getTransaction = XmlHelper.Deserialize<transaction>(creditCard.RawResult);
                    }

                    var paymetnTransaction = new PaymentTransaction();

                    getTransaction.transId = transId;
                    getTransaction.amount = processPaymentRequest.OrderTotal.ToString(CultureInfo.InvariantCulture);
                    getTransaction.tokenId = cc.Token;


                    paymetnTransaction.CreateOnUtc = DateTime.UtcNow;
                    paymetnTransaction.RawResult = XmlHelper.Serialize(getTransaction); ;
                    paymetnTransaction.Amount = processPaymentRequest.OrderTotal;
                    paymetnTransaction.CreditCardId = processPaymentRequest.CreditCardId;
                    paymetnTransaction.OrderId = processPaymentRequest.OrderId;
                    paymetnTransaction.PaymentStatus = PaymentStatus.Paid;
                    paymetnTransaction.UId = getTransaction.uID;
                    _transactionRepository.Insert(paymetnTransaction);
                }
                else
                {
                    result.AddError(_localizationService.GetResource("Plugins.Payments.Globalpayments.Errors.ProcessPayment"));

                    if (res.Errors.Count > 0)
                    {
                        result.AddError(String.Join(" | ", res.Errors));
                    }

                    if (!String.IsNullOrEmpty(res.ResponseString))
                    {
                        //string responseMessage = HttpUtility.ParseQueryString(res.ResponseString).Get("message");
                        //if (String.IsNullOrEmpty(responseMessage))
                        //{
                        //    result.AddError(res.ResponseString);
                        //}

                    }
                }
            }

            return result;
        }

        /// <summary>
        /// Post process payment (used by payment gateways that require redirecting to a third-party URL)
        /// </summary>
        /// <param name="postProcessPaymentRequest">Payment info required for an order processing</param>
        public void PostProcessPayment(PostProcessPaymentRequest postProcessPaymentRequest)
        {
            //nothing
        }

        /// <summary>
        /// Gets additional handling fee
        /// </summary>
        /// <param name="cart">Shoping cart</param>
        /// <returns>Additional handling fee</returns>
        public decimal GetAdditionalHandlingFee(IList<ShoppingCartItem> cart)
        {
            var result = this.CalculateAdditionalFee(_orderTotalCalculationService, cart,
                _globalPaymentsSettings.AdditionalFee, _globalPaymentsSettings.AdditionalFeePercentage);
            return result;
        }

        /// <summary>
        /// Captures payment
        /// </summary>
        /// <param name="capturePaymentRequest">Capture payment request</param>
        /// <returns>Capture payment result</returns>
        public CapturePaymentResult Capture(CapturePaymentRequest capturePaymentRequest)
        {
            var result = new CapturePaymentResult();
            //var order = capturePaymentRequest.Order;

            //if (order == null)
            //{
            //    result.AddError("The order cannot be found.");
            //    return result;
            //}

            //if (!order.StoreId.HasValue)
            //{
            //    result.AddError("The store ID cannot be found in the order.");
            //    return result;
            //}

            //if (order.CustomerId == 0)
            //{
            //    result.AddError("The customer ID is 0 in the order.");
            //    return result;
            //}

            //var ccId = GetCreditCardIdFromTransaction(order.CaptureTransactionId);
            //if (ccId == 0)
            //{
            //    result.AddError("CaptureTransactionId is invalid.");
            //    return result;
            //}

            //var cc = GetCreditCardById(
            //    order.CustomerId,
            //    order.StoreId.Value,
            //    ccId);

            //if (cc == null)
            //{
            //    result.AddError("The request credit card cannot be found.");
            //    return result;
            //}

            return result;
        }

        /// <summary>
        /// Refunds a payment
        /// </summary>
        /// <param name="refundPaymentRequest">Request</param>
        /// <returns>Result</returns>
        public RefundPaymentResult Refund(RefundPaymentRequest refundPaymentRequest)
        {
            Helper.FileLog(
                  "PaymentInfo",
                  "GlobalPaymentsProcessor_Refund:",
                  _globalPaymentsSettings.EnableLog);
            //return result;
            var order = refundPaymentRequest.Order;
            var result = new RefundPaymentResult();
            //int storeId = 1;

            var profile = new PaymentProfile();
            if (_globalPaymentsSettings.EnableSandbox)
            {
                // Hard coded store id, sandbox testing purpose only
                profile = _profileRepository.Table.FirstOrDefault(p => p.Id == 1);
            }
            else
            {
                profile = _profileRepository.Table.FirstOrDefault(p => p.StoreId == refundPaymentRequest.Order.StoreId.Value);
            }
            //var profile = _profileRepository.Table.FirstOrDefault(x => x.StoreId == storeId);
            var transaction = XmlHelper.Deserialize<transaction>(_globalPaymentsService.GetPaymentRawResult(order.Id));
            string transID = transaction.transId;
            string refundUid = _globalPaymentsService.GetPaymentRefundUid(order.Id).Trim();

            string resultString = GetResultCode(SendRequest(_globalPaymentsSettings.RefundUrl, profile.ProfileId, profile.ApiToken, "refund", transID, refundPaymentRequest.AmountToRefund.ToString(), refundUid));

            Helper.FileLog(
                 "PaymentInfo",
                 "GlobalPaymentsProcessor_Refund  resultString:" + resultString,
                 _globalPaymentsSettings.EnableLog);
            if (resultString == "000")
            {
                if (refundPaymentRequest.AmountToRefund >= order.OrderTotal)
                {
                    result.NewPaymentStatus = PaymentStatus.Refunded;
                }
                else
                {
                    result.NewPaymentStatus = PaymentStatus.PartiallyRefunded;
                }
            }
            return result;
        }

        /// <summary>
        /// Voids a payment
        /// </summary>
        /// <param name="voidPaymentRequest">Request</param>
        /// <returns>Result</returns>
        public VoidPaymentResult Void(VoidPaymentRequest voidPaymentRequest)
        {
            var result = new VoidPaymentResult();
            result.AddError("Void method not supported");
            return result;
        }

        /// <summary>
        /// Process recurring payment
        /// </summary>
        /// <param name="processPaymentRequest">Payment info required for an order processing</param>
        /// <returns>Process payment result</returns>
        public ProcessPaymentResult ProcessRecurringPayment(ProcessPaymentRequest processPaymentRequest)
        {
            var result = new ProcessPaymentResult();
            result.AddError("Recurring payment not supported");
            return result;
        }

        /// <summary>
        /// Cancels a recurring payment
        /// </summary>
        /// <param name="cancelPaymentRequest">Request</param>
        /// <returns>Result</returns>
        public CancelRecurringPaymentResult CancelRecurringPayment(CancelRecurringPaymentRequest cancelPaymentRequest)
        {
            var result = new CancelRecurringPaymentResult();
            result.AddError("Recurring payment not supported");
            return result;
        }

        /// <summary>
        /// Gets a value indicating whether customers can complete a payment after order is placed but not completed (for redirection payment methods)
        /// </summary>
        /// <param name="order">Order</param>
        /// <returns>Result</returns>
        public bool CanRePostProcessPayment(Order order)
        {
            if (order == null)
                throw new ArgumentNullException("order");

            //it's not a redirection payment method. So we always return false
            return false;
        }

        /// <summary>
        /// Gets a route for provider configuration
        /// </summary>
        /// <param name="actionName">Action name</param>
        /// <param name="controllerName">Controller name</param>
        /// <param name="routeValues">Route values</param>
        public void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues)
        {
            actionName = "Configure";
            controllerName = "PaymentGlobalPayments";
            routeValues = new RouteValueDictionary() { { "Namespaces", "Spotshub.Plugin.Payments.GlobalPayments.Controllers" }, { "area", null } };
        }

        /// <summary>
        /// Gets a route for payment info
        /// </summary>
        /// <param name="actionName">Action name</param>
        /// <param name="controllerName">Controller name</param>
        /// <param name="routeValues">Route values</param>
        public void GetPaymentInfoRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues)
        {
            actionName = "PaymentInfo";
            controllerName = "PaymentGlobalPayments";
            routeValues = new RouteValueDictionary() { { "Namespaces", "Spotshub.Plugin.Payments.GlobalPayments.Controllers" }, { "area", null } };
        }

        public Nop.Services.Payments.PaymentCreditCard GetCreditCard(int creditCardId = 0, int storeId = 0, bool getNewest = false, bool getDefault = false)
        {

            Helper.FileLog("GetCreditCard", string.Format("creditCardId:{0},storeId:{1},getNewest:{2},getDefault:{3}\r\n", creditCardId, storeId, getNewest, getDefault), _globalPaymentsSettings.EnableLog);

            var payment = new Nop.Services.Payments.PaymentCreditCard();

            PaymentCreditCard oneCreditCard = null;
            var customerId = _workContext.CurrentCustomer.Id;

            if (creditCardId > 0)
            {
                oneCreditCard = _creditCardRepository.Table.SingleOrDefault(p => p.Id == creditCardId);
            }
            else
            {
                oneCreditCard = getNewest ? GetNewLeastCreditCart(customerId, storeId) : GetDefaultOrFirstCreditCart(customerId, storeId);
            }

            if (oneCreditCard != null)
            {
                payment.Id = oneCreditCard.Id;
                payment.CustomerId = oneCreditCard.CustomerId;
                payment.PaymentProfileId = oneCreditCard.PaymentProfileId;
                payment.CreditCardType = oneCreditCard.CreditCardType;
                payment.CreditCardName = oneCreditCard.CreditCardName;
                payment.CreditCardNumber = oneCreditCard.CreditCardNumber;
                payment.CreditCardExpireYear = oneCreditCard.CreditCardExpireYear;
                payment.CreditCardExpireMonth = oneCreditCard.CreditCardExpireMonth;
                payment.Token = oneCreditCard.Token;
                return payment;
            }
            return null;
        }

        /// <summary>
        /// GetCreditCreads for customer
        /// </summary>
        /// <returns></returns>
        public List<Nop.Services.Payments.PaymentCreditCard> GetCreditCards()
        {
            var creditCardList = new List<Nop.Services.Payments.PaymentCreditCard>();
            var customerId = _workContext.CurrentCustomer.Id;

            var creditCards = _creditCardRepository.Table.Where(p => p.CustomerId == customerId&&p.IsDefault==false);

            foreach (var creditCard in creditCards)
            {
                var paymentCreditCard = new Nop.Services.Payments.PaymentCreditCard
                {
                    Id = creditCard.Id,
                    CustomerId = creditCard.CustomerId,
                    PaymentProfileId = creditCard.PaymentProfileId,
                    CreditCardType = creditCard.CreditCardType,
                    CreditCardName = creditCard.CreditCardName,
                    CreditCardNumber = creditCard.CreditCardNumber,
                    CreditCardExpireYear = creditCard.CreditCardExpireYear,
                    CreditCardExpireMonth = creditCard.CreditCardExpireMonth,
                    Token = creditCard.Token
                };
                creditCardList.Add(paymentCreditCard);
            }


            return creditCardList;
        }

        /// <summary>
        /// get creditecar of Last message
        /// </summary>
        /// <param name="customerId"></param>
        /// <param name="storeId"></param>
        /// <returns></returns>
        public Nop.Services.Payments.PaymentCreditCard GetCreditCardByLast(int customerId, int storeId)
        {
            var creditCartLast = GetNewLeastCreditCart(customerId, storeId);
            //var
            //return creditCart;
            var creditCart = new Nop.Services.Payments.PaymentCreditCard();
            if (creditCartLast != null && creditCartLast.IsDefault==false)
            {
                creditCart.Id = creditCartLast.Id;
                creditCart.CustomerId = creditCartLast.CustomerId;
                creditCart.PaymentProfileId = creditCartLast.PaymentProfileId;
                creditCart.CreditCardType = creditCartLast.CreditCardType;
                creditCart.CreditCardName = creditCartLast.CreditCardName;
                creditCart.CreditCardNumber = creditCartLast.CreditCardNumber;
                creditCart.CreditCardExpireYear = creditCartLast.CreditCardExpireYear;
                creditCart.CreditCardExpireMonth = creditCartLast.CreditCardExpireMonth;
                creditCart.Token = creditCartLast.Token;
            }
            return creditCart;
        }

        public Nop.Services.Payments.PaymentCreditCard GetCreditCardById(int creditCarId)
        {
            var creditCar = new Nop.Services.Payments.PaymentCreditCard();
            var getCreditCar = _globalPaymentsService.GetCreditCardById(creditCarId);
            if (getCreditCar != null && getCreditCar.IsDefault==false)
            {
                creditCar.Id = getCreditCar.Id;
                creditCar.CustomerId = getCreditCar.CustomerId;
                creditCar.PaymentProfileId = getCreditCar.PaymentProfileId;
                creditCar.CreditCardType = getCreditCar.CreditCardType;
                creditCar.CreditCardName = getCreditCar.CreditCardName;
                creditCar.CreditCardNumber = getCreditCar.CreditCardNumber;
                creditCar.CreditCardExpireYear = getCreditCar.CreditCardExpireYear;
                creditCar.CreditCardExpireMonth = getCreditCar.CreditCardExpireMonth;
                creditCar.Token = getCreditCar.Token;
                return creditCar;
            }
            return null;
        }

        public ProcessPaymentResult CreditCardPay(int creditCardId, int orderId)
        {
            var prcess = new ProcessPaymentResult();

            if (creditCardId > 0 && orderId > 0)
            {
                var order = _orderService.GetOrderById(orderId);
                if (order != null)
                {
                    if (order.StoreId == null)
                        order.StoreId = 31;
                    var processPaymentRequest = new ProcessPaymentRequest()
                    {
                        CustomerId = order.CustomerId,
                        OrderId = order.Id,
                        OrderTotal = order.OrderTotal,
                        CreditCardId = creditCardId,
                        StoreId = order.StoreId.Value,
                        PaymentMethodSystemName = order.PaymentMethodSystemName
                    };
                    return ProcessPayment(processPaymentRequest);
                }
                prcess.AddError("your order error.");
                return prcess;
            }
            prcess.AddError("please click your parameter.");
            return prcess;
            //return new { success = false, errorMessage = "error" };
        }

        public CardOnFileUrl GetSecureFormUrl(int customerId, int storeId, string type = "")
        {
            var cardOnFileUrl = new CardOnFileUrl();
            var res = _globalPaymentsService.GetCardOnFileFormUrl(customerId, storeId, type);
            if (!res.Success)
            {
                return null;
            }
            cardOnFileUrl.Uid = res.UID;
            cardOnFileUrl.Url = res.URL;
            return cardOnFileUrl;
        }

        private PaymentCreditCard GetNewLeastCreditCart(int customerId, int storeId)
        {
            if (customerId <= 0 || storeId <= 0) return null;

            return
                _globalPaymentsService.GetCreditCardsByCustomer(_workContext.CurrentCustomer.Id, storeId).OrderBy(d => d.Id)
                    .LastOrDefault();
        }

        private PaymentCreditCard GetDefaultOrFirstCreditCart(int customerId, int storeId)
        {
            if (customerId <= 0 || storeId <= 0) return null;

            var allCards = _globalPaymentsService.GetCreditCardsByCustomer(_workContext.CurrentCustomer.Id, storeId);
            if (allCards == null) return null;

            var defaultCard = allCards.FirstOrDefault(d => d.IsDefault);
            return defaultCard ?? allCards.FirstOrDefault();
        }

        public void SetDefaultCreditCard(int creditCardId, int customerId, int storeId)
        {
            if (creditCardId > 0 && customerId > 0 && storeId > 0)
            {
                var creditCards = _globalPaymentsService.GetCreditCardsByCustomer(customerId, storeId);
                if (creditCards.Count > 0)
                {
                    foreach (var creditCard in creditCards)
                    {
                        if (creditCard.Id == creditCardId)
                        {
                            creditCard.IsDefault = true;
                            _creditCardRepository.Update(creditCard);
                        }
                        else if (creditCard.IsDefault == true)
                        {
                            creditCard.IsDefault = false;
                            _creditCardRepository.Update(creditCard);
                        }
                    }
                }
            }
        }

        public bool AddPaymentsTransaction(int orderId, decimal amount, int creditCardId, string tokenId, out string message)
        {

            var isResult = AddPayments(orderId, amount, creditCardId, tokenId, out message);
            return isResult;
        }

        public bool AddPaymentsTransaction(List<int> orderId, decimal amount, int creditCardId, string tokenId, out string message)
        {
            message = string.Empty;
            int[] orderInts = new int[orderId.Count];
            orderId.CopyTo(orderInts);
            var orderList = _orderService.GetOrdersByIds(orderInts).ToList<Order>();
            if (orderList.Count <= 0) return false;

            var isResult = AddPayments(orderList, amount, creditCardId, tokenId, out message);

            return isResult;
        }

        public bool AddPaymentsTransaction(decimal amount, int creditCardId, string tokenId, out string message)
        {
            var isResult = AddPayments(null, amount, creditCardId, tokenId, out message);
            return isResult;
        }


        private bool AddPayments(int orderId, decimal amount, int creditCardId, string tokenId, out string message)
        {
            var order = _orderService.GetOrderById(orderId);
            var orderList = new List<Order> { order };
            var isSave = SavePaymentTransaction(orderList, amount, creditCardId, tokenId, out message);
            return isSave;
        }


        private bool AddPayments(List<Order> orderIds, decimal amount, int creditCardId, string tokenId, out string message)
        {
            var isSave = SavePaymentTransaction(orderIds, amount, creditCardId, tokenId, out message);
            return isSave;
        }

        private bool SavePaymentTransaction(List<Order> order, decimal amount, int creditCardId, string tokenId, out string message)
        {
            try
            {
                if (order == null || order.Count == 0)
                    throw new NopException("{0} is Null", "List<Order>");
                if (amount <= 0)
                    throw new NopException("{0} is greater than zero", "amount");

                if (string.IsNullOrEmpty(tokenId))
                    throw new NopException("{0} is greater than zero", "tokenId");

                message = string.Empty;

                var orderSingle = order.FirstOrDefault();
                if (orderSingle == null) return false;

                var storeId = orderSingle.StoreId == null ? 23 : orderSingle.StoreId.Value;

                //_globalPaymentsSettings.RefundUrl = "https://direct.sandbox-gtpaysecure.net/direct/services/authorize/";
                var tokenUrl = _globalPaymentsSettings.DirectServiceUrl + _globalPaymentsSettings.AuthorizeEndpoint;
                if (_globalPaymentsSettings.EnableSandbox)
                    tokenUrl = _globalPaymentsSettings.SandboxDirectServiceUrl + _globalPaymentsSettings.AuthorizeEndpoint;

                var profile = _profileRepository.Table.FirstOrDefault(x => x.StoreId == storeId);
                var profileId = profile.ProfileId;
                var apiToken = profile.ApiToken;
                if (_globalPaymentsSettings.EnableSandbox && !String.IsNullOrEmpty(_globalPaymentsSettings.SandboxProfileId) && !String.IsNullOrEmpty(_globalPaymentsSettings.SandboxAPIToken))
                {
                    profileId = _globalPaymentsSettings.SandboxProfileId;
                    apiToken = _globalPaymentsSettings.SandboxAPIToken;
                }
                var returnUrl = SendRequestToken(tokenUrl, profileId, apiToken, tokenId, amount.ToString());
                var resultString = GetResultCode(returnUrl);
                if (resultString == "000")
                {
                    var transId = GetResultCode(returnUrl, "TxnGUID");
                    //var onePaymentsTransaction = _transactionRepository.Table.FirstOrDefault(i => i.CreditCardId == creditCardId && i.OrderId == 0);

                    var paymentsCreditCard = _creditCardRepository.Table.FirstOrDefault(i => i.Id == creditCardId);
                    if (paymentsCreditCard == null)
                        throw new NopException("{0} is Null", "onePaymentsTransaction");
                    var getTransaction = new transaction();
                    if (!String.IsNullOrEmpty(paymentsCreditCard.RawResult))
                        getTransaction = XmlHelper.Deserialize<transaction>(paymentsCreditCard.RawResult);
                    var rawXml = "";

                    var paymetnTransaction = new PaymentTransaction();
                    foreach (var oneOrder in order)
                    {
                        getTransaction.transId = transId;
                        getTransaction.merchantPass = profile.ProfileId;
                        getTransaction.amount = amount.ToString(CultureInfo.InvariantCulture);
                        getTransaction.tokenId = tokenId;
                        //rawXml = CommonHelper.To<string>(getTransaction);
                        rawXml = XmlHelper.Serialize(getTransaction);

                        paymetnTransaction.CreateOnUtc = DateTime.UtcNow;
                        paymetnTransaction.RawResult = rawXml;
                        paymetnTransaction.Amount = amount;
                        paymetnTransaction.CreditCardId = creditCardId;
                        paymetnTransaction.OrderId = oneOrder.Id;
                        paymetnTransaction.PaymentStatus = PaymentStatus.Paid;
                        paymetnTransaction.UId = getTransaction.uID;
                        _transactionRepository.Insert(paymetnTransaction);
                        oneOrder.PaymentStatusId = (int)PaymentStatus.Paid;
                        _orderService.UpdateOrder(oneOrder);
                    }
                    return true;
                }
                message = GetResultCode(returnUrl, "message");
                return false;
            }
            catch (Exception ex)
            {
                throw (ex);
            }
        }

        /// <summary>
        /// Gets controller type
        /// </summary>
        /// <returns></returns>
        public Type GetControllerType()
        {
            return typeof(PaymentGlobalPaymentsController);
        }

        /// <summary>
        /// Install
        /// </summary>
        public override void Install()
        {
            //settings
            var settings = new GlobalPaymentsSettings()
            {
                TestIframeUrl = "https://safe.sandbox-gtpaysecure.net/hpf/1_1/?amount=&collectAddress=0&action=buildForm&trans_type=&merchPass=&allowed_types=Visa|MasterCard|American Express|Discover|GSA SmartPay&cre_tokenize=store_only&sessionId=&currency_code=CAD&name=Sample&nbsp;User&formType=1",
                EnableLog = true,
                EnableDebug = false,
                SampleResponse = "success_response.xml",

                AdditionalFee = 0,
                AdditionalFeePercentage = false,
                FormUrl = "https://safe.gtpaysecure.net/hpf/1_1/",
                DirectServiceUrl = "https://direct.gtpaysecure.net/direct/services/",
                AllowedTypes = "Visa|MasterCard",
                AuthorizeEndpoint = "authorize/",
                QueryEndpoint = "request/query/",
                UIDEndpoint = "request/init/",
                CallbackUrl = "",
                CssUrl = "",
            };
            _settingService.SaveSetting(settings);

            _objectContext.Install();

            //locales
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.TestUrl", "Test URL");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.TestUrl.Hint", "Test URL");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.EnableDebug", "Enable Debug");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.EnableDebug.Hint", "Enable Debug");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.EnableLog", "Enable Log");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.EnableLog.Hint", "Enable Log");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.AdditionalFee", "Additional Fee");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.AdditionalFee.Hint", "Additional Fee");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.AdditionalFeePercentage", "Additional Fee Percentage");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.AdditionalFeePercentage.Hint", "Additional Fee Percentage");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.FormUrl", "IFrame form URL");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.FormUrl.Hint", "IFrame form URL");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.DirectServiceUrl", "Direct Service URL");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.DirectServiceUrl.Hint", "Direct Service URL");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.AllowedTypes", "Allowed card types");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.AllowedTypes.Hint", "Allowed card types");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.AuthorizeEndpoint", "Authorize URL");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.AuthorizeEndpoint.Hint", "Authorize URL");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.QueryEndpoint", "Query URL");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.QueryEndpoint.Hint", "Query URL");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.UIdEndpoint", "UID URL");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.UIdEndpoint.Hint", "UID URL");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.CallbackUrl", "Callback URL");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.CallbackUrl.Hint", "Callback URL");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.CssUrl", "CSS URL");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.CssUrl.Hint", "CSS URL");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.ProfileId", "Profile ID");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.ProfileId.Hint", "Profile ID");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.ApiToken", "API Token");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.ApiToken.Hint", "API Token");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.Store", "Store");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.Store.Hint", "Store");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.Type", "Additional Account Type");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.Type.Hint", "Additional Account Type");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.Globalpayments.Editprofile", "Edit Profile");
            this.AddOrUpdatePluginLocaleResource("Plugins.Payments.Globalpayments.Errors.ProcessPayment", "Fatal server error when processing payment.");

            base.Install();
        }

        public override void Uninstall()
        {
            //settings
            _settingService.DeleteSetting<GlobalPaymentsSettings>();

            _objectContext.Uninstall();

            //locales
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.TestUrl");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.TestUrl.Hint");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.EnableDebug");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.EnableDebug.Hint");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.EnableLog");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.EnableLog.Hint");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.AdditionalFee");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.AdditionalFee.Hint");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.AdditionalFeePercentage");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.AdditionalFeePercentage.Hint");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.FormUrl");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.FormUrl.Hint");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.DirectServiceUrl");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.DirectServiceUrl.Hint");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.AllowedTypes");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.AllowedTypes.Hint");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.AuthorizeEndpoint");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.AuthorizeEndpoint.Hint");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.QueryEndpoint");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.QueryEndpoint.Hint");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.UIdEndpoint");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.UIdEndpoint.Hint");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.CallbackUrl");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.CallbackUrl.Hint");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.CssUrl");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.CssUrl.Hint");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.ProfileId");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.ProfileId.Hint");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.ApiToken");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.ApiToken.Hint");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.Store");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.Store.Hint");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.Type");
            this.DeletePluginLocaleResource("Plugins.Payments.GlobalPayments.Fields.Type.Hint");
            this.DeletePluginLocaleResource("Plugins.Payments.Globalpayments.Editprofile");
            this.DeletePluginLocaleResource("Plugins.Payments.Globalpayments.Errors.ProcessPayment");


            base.Uninstall();
        }

        #endregion

        #region Properies

        /// <summary>
        /// Gets a value indicating whether capture is supported
        /// </summary>
        public bool SupportCapture
        {
            get
            {
                return true;
            }
        }

        /// <summary>
        /// Gets a value indicating whether partial refund is supported
        /// </summary>
        public bool SupportPartiallyRefund
        {
            get
            {
                return true;
            }
        }

        /// <summary>
        /// Gets a value indicating whether refund is supported
        /// </summary>
        public bool SupportRefund
        {
            get
            {
                return true;
            }
        }

        /// <summary>
        /// Gets a value indicating whether void is supported
        /// </summary>
        public bool SupportVoid
        {
            get
            {
                return false;
            }
        }

        /// <summary>
        /// Gets a recurring payment type of payment method
        /// </summary>
        public RecurringPaymentType RecurringPaymentType
        {
            get
            {
                return RecurringPaymentType.Automatic;
            }
        }

        /// <summary>
        /// Gets a payment method type
        /// </summary>
        public PaymentMethodType PaymentMethodType
        {
            get
            {
                return PaymentMethodType.Standard;
            }
        }

        public bool SkipPaymentInfo
        {
            get { return false; }
        }

        #endregion

        #region Utilities


        #region Repository


        #endregion

        #endregion

    }
}
